/*
 * @Author       : Bing Chen chenbing@iocharger.com
 * @Date         : 2025-01-21 16:09:28
 * @LastEditors  : Bing Chen chenbing@iocharger.com
 * @LastEditTime : 2025-03-15 13:05:59
 * @FilePath     : \openchaoji-corelib\x86\evcc\app_compile_evcc_x86.c
 * @Description  :
 *
 * Copyright (c) 2025 OpenChaoJi
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the icense for the specific language governing permissions and
 * limitations under the License.
 *
 */
#include "../../evcc/include/OpenChaoJi_evcc.h"

#include "../app_hal_x86.h"
#include "evcc_x86.h"

/* X86 GCC 测试程序 */

static struct OpenChaoJi_evcc_context * s_evcc_context[HAL_SIMU_CONNECTOR_NUM] = {NULL, NULL};
static struct OpenChaoJi_evcc_context_create_info s_evcc_create_info[HAL_SIMU_CONNECTOR_NUM];
static struct OpenChaoJi_evcc_app_start_parameter s_evcc_app_parameter[HAL_SIMU_CONNECTOR_NUM];
static struct OpenChaoJi_evcc_context_status s_evcc_app_status[HAL_SIMU_CONNECTOR_NUM];

static void evcc_app_one_init(int idx)
{
#if (OPENCHAOJI_CONFIG_ENABLE_GBT27930_A == CONFIG_YES)
    if (idx == 0)
    {
        memset(&s_evcc_create_info[idx], 0x00, sizeof(s_evcc_create_info[idx]));

        s_evcc_create_info[idx].tag = 0;
        s_evcc_create_info[idx].hal_handle = evcc_hal_one_handle(idx);
        s_evcc_create_info[idx].evcc_gbt27930_type = OPENCHAOJI_EVCC_GBT27930_TYPE_A;
        s_evcc_create_info[idx].secc_gbt27930_type_compatibility = OPENCHAOJI_SECC_GBT27930_TYPE_A;

        s_evcc_create_info[idx].pilot.tag = s_evcc_create_info[idx].tag;
        s_evcc_create_info[idx].pilot.hal_handle = s_evcc_create_info[idx].hal_handle;
        s_evcc_create_info[idx].pilot.evcc_gbt27930_type = s_evcc_create_info[idx].evcc_gbt27930_type;

        s_evcc_create_info[idx].session.tag = s_evcc_create_info[idx].tag;
        s_evcc_create_info[idx].session.hal_handle = s_evcc_create_info[idx].hal_handle;
        s_evcc_create_info[idx].session.evcc_gbt27930_type = s_evcc_create_info[idx].evcc_gbt27930_type;

        s_evcc_create_info[idx].session.data_buff.tag = s_evcc_create_info[idx].tag;
        s_evcc_create_info[idx].session.data_buff.recv_capacity = 4;

        s_evcc_create_info[idx].session.linkage.tag = s_evcc_create_info[idx].tag;
        s_evcc_create_info[idx].session.linkage.gbt27930_info.gbt27930_a.dummy = 0;
        s_evcc_create_info[idx].session.linkage.tag = s_evcc_create_info[idx].tag;
        s_evcc_create_info[idx].session.linkage.hal_handle = s_evcc_create_info[idx].hal_handle;
        s_evcc_create_info[idx].session.linkage.evcc_gbt27930_type = s_evcc_create_info[idx].evcc_gbt27930_type;

        memset(&s_evcc_app_parameter[idx], 0x00, sizeof(s_evcc_app_parameter[idx]));

        s_evcc_app_parameter[idx].parameter_max_charging_volt = 7500;
        s_evcc_app_parameter[idx].parameter_max_charging_curr = 2500;

        memset(&s_evcc_app_status[idx], 0x00, sizeof(s_evcc_app_status[idx]));
    }
#endif
#if (OPENCHAOJI_CONFIG_ENABLE_GBT27930_B == CONFIG_YES)
    if (idx == 1)
    {
        s_evcc_create_info[idx].tag = 1;
        s_evcc_create_info[idx].hal_handle = evcc_hal_one_handle(idx);
        s_evcc_create_info[idx].evcc_gbt27930_type = OPENCHAOJI_EVCC_GBT27930_TYPE_B;

        s_evcc_create_info[idx].pilot.hal_handle = s_evcc_create_info[idx].hal_handle;
        s_evcc_create_info[idx].pilot.evcc_gbt27930_type = s_evcc_create_info[idx].evcc_gbt27930_type;

        s_evcc_create_info[idx].session.hal_handle = s_evcc_create_info[idx].hal_handle;
        s_evcc_create_info[idx].session.evcc_gbt27930_type = s_evcc_create_info[idx].pilot.evcc_gbt27930_type;

        s_evcc_create_info[idx].session.gbt27930_info.gbt27930_b.dummy = 0;

        s_evcc_create_info[idx].session.data_buff.recv_capacity = 4;

        s_evcc_create_info[idx].session.linkage.gbt27930_info.gbt27930_a.dummy = 0;
        s_evcc_create_info[idx].session.linkage.gbt27930_info.gbt27930_b.can_type	 = OPENCHAOJI_GBT27930_B_CAN_TYPE_20;
        s_evcc_create_info[idx].session.linkage.gbt27930_info.gbt27930_b.evcc_version = OPENCHAOJI_GBT27930_B_PROTOCOL_VERSION_TYPE_2_0_0;
        s_evcc_create_info[idx].session.linkage.tag = s_evcc_create_info[idx].tag;
        s_evcc_create_info[idx].session.linkage.hal_handle = s_evcc_create_info[idx].hal_handle;
        s_evcc_create_info[idx].session.linkage.evcc_gbt27930_type = s_evcc_create_info[idx].pilot.evcc_gbt27930_type;

        memset(&s_evcc_app_parameter[idx], 0x00, sizeof(s_evcc_app_parameter[idx]));
        s_evcc_app_parameter[idx].fdc_auth[1]       = OPENCHAOJI_GBT27930_B_FDC_SUPPORT_TYPE_SUPPORT;
        s_evcc_app_parameter[idx].fdc_selfcheck[0]  = OPENCHAOJI_GBT27930_B_FDC_SUPPORT_TYPE_SUPPORT;
        s_evcc_app_parameter[idx].fdc_energy[0]     = OPENCHAOJI_GBT27930_B_FDC_SUPPORT_TYPE_SUPPORT;
        s_evcc_app_parameter[idx].fdc_statistics[0] = OPENCHAOJI_GBT27930_B_FDC_SUPPORT_TYPE_SUPPORT;

        s_evcc_app_parameter[idx].parameter_max_charging_volt = 7500;
        s_evcc_app_parameter[idx].parameter_max_charging_curr = 2500;

        memset(&s_evcc_app_status[idx], 0x00, sizeof(s_evcc_app_status[idx]));
    }
#endif

    return;
}

void evcc_app_init()
{
    int idx;

    OpenChaoJi_os_memeory_init();

    // 设置默认的打印级别, 后续运行时App可以根据实际情况调用此方法修改打印级别以获得不同程度的调试信息
    OpenChaoJi_debug_set_log_level(   DEFAULT_DBG_LEVEL
                                        // | DBGL_INFO
                                        // | DBGL_DEBUG
                                        );

    for (idx = 0; idx < HAL_SIMU_CONNECTOR_NUM; idx++)
    {
        // 厂家首先需要初始化HAL层
        evcc_hal_one_init(idx);

        // 创建上下文, 上下文将是后续所有模块通信的唯一句柄
        evcc_app_one_init(idx);

        s_evcc_context[idx] = OpenChaoJi_evcc_create_context(&s_evcc_create_info[idx]);
        if (s_evcc_context[idx] == NULL)
        {
            continue;
        }
    }
}

void evcc_app_term()
{
    for (int idx = 0; idx < HAL_SIMU_CONNECTOR_NUM; idx++)
    {
        evcc_hal_one_term(idx);

        if (s_evcc_context[idx] != NULL)
        {
            OpenChaoJi_evcc_destroy_context(s_evcc_context[idx]);
        }
    }


    OpenChaoJi_os_memeory_term();
}

static bool evcc_app_one_check_start(int idx)
{
    char file_name[30];
    sprintf(file_name, "/tmp/evcc_appstart_%d", idx);

    if (access(file_name, F_OK) == 0)
    {
        remove(file_name);

        evcc_hal_one_reset(idx);

        evcc_hal_one_plug(idx, true);    // 由EVCC这边启动的时候模拟插枪

        return true;
    }

    return false;
}

static bool evcc_app_one_is_starting(int idx)
{
#if (OPENCHAOJI_CONFIG_ENABLE_GBT27930_B == CONFIG_YES)
    if (s_evcc_context[idx]->evcc_gbt27930_type == OPENCHAOJI_EVCC_GBT27930_TYPE_B)
    {
        return ((s_evcc_app_status[idx].current_module_status_id > OPENCHAOJI_GBT27930_B_EVCC_STATUS_ID_IDLE_S0_IDLE)
        && (s_evcc_app_status[idx].current_module_status_id < OPENCHAOJI_GBT27930_B_EVCC_STATUS_ID_STOPING_S0_NORMAL));
    }
#endif

#if (OPENCHAOJI_CONFIG_ENABLE_GBT27930_A == CONFIG_YES)
    if (s_evcc_context[idx]->evcc_gbt27930_type == OPENCHAOJI_EVCC_GBT27930_TYPE_A)
    {
        return ((s_evcc_app_status[idx].current_module_status_id > OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_IDLE_S0_IDLE)
        && (s_evcc_app_status[idx].current_module_status_id < OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_END_S0_INIT));
    }
#endif

    return false;
}

static bool evcc_app_one_check_stop(int idx)
{
    char file_name[30];
    sprintf(file_name, "/tmp/evcc_appstop_%d", idx);

    if (access(file_name, F_OK) == 0)
    {
        remove(file_name);

        return true;
    }

    if (evcc_app_one_is_starting(idx))
    {
        if (evcc_hal_one_get_battery_soc_reached(idx))
        {
            LOG_ALERT("[%d]SoC reached");
            return true;
        }
    }

    return false;
}

static bool evcc_app_one_check_plug(int idx)
{
    char file_name[30];

    sprintf(file_name, "/tmp/evcc_plugin_%d", idx);
    if (access(file_name, F_OK) == 0)
    {
        remove(file_name);

        evcc_hal_one_plug(idx, true);
        return true;
    }

    sprintf(file_name, "/tmp/evcc_plugout_%d", idx);
    if (access(file_name, F_OK) == 0)
    {
        remove(file_name);

        evcc_hal_one_plug(idx, false);
        return true;
    }

    return false;
}


void evcc_app_service()
{
    // 运行时实时修改打印级别

    for (int idx = 0; idx < HAL_SIMU_CONNECTOR_NUM; idx++)
    {
        if (s_evcc_context[idx] != NULL)
        {
            evcc_hal_one_service(idx);

            // 检查插拔枪和启动停止
            evcc_app_one_check_plug(idx);

            if (evcc_app_one_check_start(idx))
            {
                s_evcc_context[idx]->active_evcc_gbt27930_system->app_start_func(s_evcc_context[idx], &s_evcc_app_parameter[idx]);
            }
            if (evcc_app_one_check_stop(idx))
            {
                s_evcc_context[idx]->active_evcc_gbt27930_system->app_stop_func(s_evcc_context[idx]);
            }

            // 更新实时状态
            s_evcc_context[idx]->active_evcc_gbt27930_system->app_get_status_func(s_evcc_context[idx], &s_evcc_app_status[idx]);

            // 执行serivce
            OpenChaoJi_evcc_service(s_evcc_context[idx]);
        }
    }
}


void interrupt_emergency_a()
{
    OpenChaoJi_evcc_service(s_evcc_context[0]);
}

void interrupt_emergency_b()
{
    OpenChaoJi_evcc_service(s_evcc_context[1]);
}

void OpenChaoJi_evcc_app_get_charging_requirement(struct OpenChaoJi_evcc_context * context, struct OpenChaoJi_evcc_gbt27930_charging_requirement_parameter * charging_requirement_evcc)
{
    for (int idx = 0; idx < HAL_SIMU_CONNECTOR_NUM; idx++)
    {
        if (s_evcc_context[idx] == context)
        {
            charging_requirement_evcc->voltage = evcc_hal_one_get_battery_request_voltage(idx);
            charging_requirement_evcc->current = evcc_hal_one_get_battery_request_current(idx); // TODO: 实际这里还需要跟SECC给出的最大电流/最大功率进行比较计算.

#if (OPENCHAOJI_CONFIG_ENABLE_GBT27930_B == CONFIG_YES)
            if (s_evcc_context[idx]->evcc_gbt27930_type == OPENCHAOJI_EVCC_GBT27930_TYPE_B)
                charging_requirement_evcc->charge_mode = OPENCHAOJI_GBT27930_B_CHARGE_MODE_TYPE_CURRENT;
#endif
#if (OPENCHAOJI_CONFIG_ENABLE_GBT27930_A == CONFIG_YES)
            if (s_evcc_context[idx]->evcc_gbt27930_type == OPENCHAOJI_EVCC_GBT27930_TYPE_A)
                charging_requirement_evcc->charge_mode = OPENCHAOJI_GBT27930_A_CHARGE_MODE_TYPE_CURRENT;
#endif
            return;
        }
    }
}

#if (OPENCHAOJI_CONFIG_ENABLE_GBT27930_B == CONFIG_YES)
int  OpenChaoJi_evcc_app_get_auth_status(struct OpenChaoJi_evcc_context * context)
{
    return  OPENCHAOJI_GBT27930_B_EVCC_AUTH_STATUS_WAIT_CONTINUE;
}
#endif
